/**
 * @description: 封装的webScoket
 * @fileName: webScoket
 * @author: 17076
 * @date: 2025/3/19-下午2:51
 * @version: V1.0.0
 **/
export default class WS {
  /**
   * WebSocket 高阶封装
   * @param {Object} config 配置项
   * @param {string} config.url 连接地址
   * @param {number} [config.reconnectLimit=3] 重连次数限制
   * @param {number} [config.reconnectInterval=3000] 重连延迟(ms)
   * @param {number} [config.heartInterval=5000] 心跳间隔(ms)
   * @param {string} [config.heartMsg='__HEART__'] 心跳消息内容
   */
  constructor(config) {
    // 初始化配置
    this.config = Object.assign({
      reconnectLimit: 3,
      reconnectInterval: 3000,
      heartInterval: 5000,
      heartMsg: '__HEART__'
    }, config)

    // 运行时状态
    this.ws = null
    this.reconnectCount = 0
    this.messageQueue = []
    this.events = new Map()
    this.heartTimer = null
    this.reconnectTimer = null
    this.isManualClose = false

    // 自动连接
    this.connect()
  }

  // 核心方法 --------------------------------------------------------
  connect() {
    if (this.ws) return

    this.ws = new WebSocket(this.config.url)
    this.bindEvent()
  }

  send(data, type = 'json') {
    return new Promise((resolve, reject) => {
      if (this.ws?.readyState === WebSocket.OPEN) {
        try {
          const payload = this.serialize(data, type)
          this.ws.send(payload)
          resolve()
        } catch (error) {
          reject(error)
        }
      } else {
        this.messageQueue.push({ data, type, resolve, reject })
      }
    })
  }

  close(code = 1000, reason = 'normal close') {
    this.isManualClose = true
    this.ws?.close(code, reason)
  }

  // 事件管理 --------------------------------------------------------
  on(event, callback) {
    this.events.set(event, callback)
  }

  off(event) {
    this.events.delete(event)
  }

  // 内部方法 --------------------------------------------------------
  bindEvent() {
    this.ws.onopen = (e) => {
      this.reconnectCount = 0
      this.trigger('open', e)
      this.flushMessageQueue()
      this.startHeartbeat()
    }

    this.ws.onmessage = (e) => {
      this.trigger('message', this.parseData(e.data))
      this.resetHeartbeat()
    }

    this.ws.onerror = (e) => {
      this.trigger('error', e)
      this.reconnect()
    }

    this.ws.onclose = (e) => {
      this.trigger('close', e)
      this.ws = null
      if (!this.isManualClose) this.reconnect()
    }
  }

  reconnect() {
    if (this.reconnectCount >= this.config.reconnectLimit) {
      return this.trigger('reconnect-failed')
    }

    clearTimeout(this.reconnectTimer)
    this.reconnectTimer = setTimeout(() => {
      this.reconnectCount++
      this.connect()
      this.trigger('reconnect', this.reconnectCount)
    }, this.config.reconnectInterval)
  }

  // 心跳检测 --------------------------------------------------------
  startHeartbeat() {
    clearInterval(this.heartTimer)
    this.heartTimer = setInterval(() => {
      this.send(this.config.heartMsg, 'text')
    }, this.config.heartInterval)
  }

  resetHeartbeat() {
    clearInterval(this.heartTimer)
    this.startHeartbeat()
  }

  // 数据处理 --------------------------------------------------------
  serialize(data, type) {
    const types = {
      json: () => JSON.stringify(data),
      text: () => String(data),
      blob: () => new Blob([data]),
      arraybuffer: () => data instanceof ArrayBuffer ? data : new TextEncoder().encode(data)
    }
    return types[type] ? types[type]() : data
  }

  parseData(data) {
    try {
      return JSON.parse(data)
    } catch {
      return data
    }
  }

  // 队列管理 --------------------------------------------------------
  flushMessageQueue() {
    while (this.messageQueue.length) {
      const msg = this.messageQueue.shift()
      this.send(msg.data, msg.type)
        .then(msg.resolve)
        .catch(msg.reject)
    }
  }

  // 事件触发 --------------------------------------------------------
  trigger(event, ...args) {
    const callback = this.events.get(event)
    callback?.apply(null, args)
  }
}

